随笔 - 26  文章 - 0 评论 - 15 trackbacks - 0

转自  http://blog.csdn.net/laobai_2006/article/details/3124719

 

闲话少说(一直就没少说),老白一直在维护的某系统中有个用 Java 写的生成唯一标识的类,主要是靠“Calendar.getInstance().getTimeInMillis()”来获取所谓毫秒级的长整型数值。条件所限,老白现在需要用 .NET 来实现同样的功能,于是想当然地使用了“DataTime.Now.Ticks”。

正如你可能知道的,“DataTime.Now.Ticks”虽然的确也是 long(Int64) 类型的,但其数值的时间单位和 Java 那个就不一样,是 100 nanosecond(100纳秒,10-7 秒),而非 1 millisecond(1毫秒,10-3 秒)。这倒不是什么大事儿(还不大呢,差着数量级呢),把“DateTime.Now.Ticks”得到的数值除以 10000 就完了呗……没那么简单!

通过一番调查取证,老白才发现,人家 Java 是从 1970-01-01 00:00:00.000 开始算的毫秒数,有文档为证:

"getTimeInMillis() ... Returns: the current time as UTC milliseconds from the epoch." fromhttp://java.sun.com/j2se/1.5.0/docs/api/java/util/Calendar.html#getTimeInMillis()

所谓的 epoch 就是 1970-01-01 00:00:00.000 这个时刻(不知道背后还有什么故事没有,欢迎知情者分享)。

.NET 呢?她是从 0001-01-01 00:00:00.000 开始算的,数就大很多了。MSDN 里关于 DateTime.Ticks 是这样说的:

"The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001." from http://msdn.microsoft.com/en-us/library/system.datetime.ticks(VS.80).aspx

所以,除了数值采用的单位不同,二者计数的时间起点也不同。最后的结论就是,如果想用 .NET 的 System.DateTime.Now.Ticks 来实现 Java 的 java.util.Calendar.getInstance().getTimeInMillis() 的话,你可以采取类似“(DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000”的办法,当然,我是用的“(DateTime.Now.Ticks - 621355968000000000) / 10000”,一个意思一个意思。

看看我这回都说了些什么:

 


java.util.Calendar.getTimeInMillis()System.DateTime.Ticks
数据类型long
long
时间单位millisecond
100 nanosecond
计时起点1970-01-01 00:00:00.000
0001-01-01 00:00:00.000

 

事后有热心的朋友提醒我,像我这样对 long 做除法会出误差(不能整除的时候),他们 Java Developer 都用 BigDecimal,不然会被笑话的。那行,赶紧的,.NET 里就用 Decimal 吧?

 

  1.          public   long  getTimeInMillis()
  2.         {
  3.              return  Decimal.ToInt64(Decimal.Divide(DateTime.Now.Ticks - 621355968000000000, 10000));
  4.         }

再后来,发现这其实是一个 Unix 时间和 .NET 时间表示法的相互转换问题。老白这才想起来,Linux 时间就是从 Epoch 开始算的,只是当时不知道 1970-01-01 00:00:00.000 有个学名叫“Epoch”。

 

还没完,请往下看!!!

重要补充:热心读者 mobdx_19840908 敏锐地指出了本文的致命错误(参见评论)~~~ 简单说来就是使用 DateTime.Now 的时候没有注意时区问题!老白自己也在上文中说了 Java 是以 UTC 为基准的,而经查证,.NET 中与其对应的是 DateTime.UtcNow 而非 DateTime.Now!

 

所以,最后的结论就是:

 

return Decimal.ToInt64(Decimal.Divide(DateTime.Now.Ticks - new DateTime(1970, 1, 1, 8, 0, 0).Ticks, 10000))

 

或者

 

return Decimal.ToInt64(Decimal.Divide(DateTime.UtcNow.Ticks - 621355968000000000, 10000));

posted @ 2011-09-13 18:26 芝麻开门 阅读(687) 评论(0) 编辑
转载自  
http://robbin.iteye.com/blog/1136859

robbin的自言自语

从ITeye(JavaEye)被CSDN收购,我从上海搬家到北京上班,眨眼之间已经过去了一年多。回顾过去这一年,生活环境发生了巨大改变,工作的职 责和角色也重新定位,面临了一些新的困难和挑战。总体来说,感觉自己这一年过得很充实,很有成就感,在公司的大力支持下,计划做并且花了时间和精力努力的 事情基本都做成了,如果要给自己打分的话,我会打80分。那剩下的20分代表本计划去做却没有时间或者精力做的事情。希望在未来的一年,可以把我剩下的 20分也做好。

2010年3月 - 2010年8月

2010年3月底我到CSDN报道,接手了公司研发部门和产品运营部门,负责CSDN(包括ITeye)网站所有产品,研发,系统运维,网站运营 的工作,不过一直到8月我经常不在北京:一方面经常往返北京和上海处理公司并购的事情;另一方面因为母亲病重常常回家照顾。这段时间主要是熟悉公司的状 况,了解部门业务和员工。当时部门士气很低落,两个部门总共17个员工,在我接手部门前已经有两个员工提出了辞职,后来陆续有员工离开,到8月底部门剩下 了10个人。考虑到自己也是新人,需要时间了解和适应公司,另外刚刚空降,应安抚老员工保证部门正常运转,因此这段时间做了几项有针对性的改良措施:

1、两个部门人员很少,部门之间协作却存在互相推诿;我和基层员工隔了部门主管,团队经理两个层级,不利于深入业务层面进行调整。因此进行了组织架构调整:合并两个部门取消部门主管层级,改设5个团队,团队经理直接向我汇报,减少管理层级,提高执行效率。
2、逐步建立和完善部门规范的管理制度,如:使用JIRA进行整个部门的工作任务量化管理;建立定期周会,周报和月报制度;我亲自制定了部门绩效考评内容、评分标准和奖励等级;要求团队间工作配合必须邮件书面确认抄送给我等等。
3、针对公司过去跨部门配合出现的混乱状况,明确了本部门和公司其他部门合作流程,并要求跨部门合作必须抄送我和相应部门高管,得到我邮件确认才准执行。
4、针对公司过去产品无规划无设计的状况,设立产品团队,制定产品设计流程,我兼任产品经理主抓产品,并开始培养产品设计人员。

在我来公司前,CSDN无产品设计和研发流程,无论部门内部还是跨部门产品研发,都是业务人员直接找负责该产品线的程序员下命令修改;大的产品研 发,业务人员找UI设计人员做一套页面就发给程序员要求XX时间完成,相互之间缺乏沟通:一方面程序员反感和抵制没头没脑的需求和毫无计划性的产品变更, 觉得自己被使唤来使唤去在公司没地位;另一方面UI设计人员被迫承担了本应该是产品经理的需求搜集和产品设计工作,盲人摸象的做完就交差;最后是业务人员 抱怨UI设计人员和程序员根本不配合,觉得他们都是大爷哄着才能干活。结果团队之间部门之间推卸责任,事情做不好只怪对方不给力,自己全然没责任。

针对这种状况我设立了产品团队,亲自兼任产品经理把所有产品都抓过来统一管理。无论部门内部还是跨部门产品研发,统一走产品设计流程:所有产品先 经我批准,然后在产品团队立项,走产品原型设计流程,接着才是UI设计和页面制作,最后才是程序员研发。从源头上狠抓产品原型设计,在原型设计阶段反复推 敲和修改,慎重的对待每项产品功能,避免了后续UI反复推翻页面设计,程序员反复改产品的大问题。从CSDN产品角度来说这段时间做了一些小的产品改进, 如主题课堂,织梦内容发布系统,投票评论留言,新浪微博整合等,但主要工作在梳理CSDN混乱的产品线,通过两次清理,关闭了100多个废弃或者很少被使 用的子网站和域名,关闭了很多鸡肋性质的频道,以及核心产品的鸡肋功能。

这几个月虽然做了大量的部门建设工作,员工士气得到了很大的提高,但员工流失仍然在继续。而且我反复强调的工作理念得不到良好的贯彻执行,员工完成的任务质量离我心中的标准差距很大。

2010年9月 - 2011年1月

2010年8月底我彻底base在北京办公,这个时候部门员工只有10个人:3个程序员,3个社区运营和客服,2个网站运维,1个产品设计,1个 UI制作,巧妇难为无米之炊。所以9月和10月在公司支持下进行了一轮大规模招聘,总共招聘了10名新员工,重新build了整个部门团队,开始取得了一 些成绩,但也遇到了非常大的困难。

在部门团队build方面:设立了PHP,.net和Ruby三个研发团队,分别负责不同的产品线;公司整个UI团队也划到我部门管理;网站的社 区运营方面增设了内容审核团队,后来我又将运营团队分拆成CSDN运营和ITeye运营两个团队,加上原有的产品设计和运维,总共有8个团队经理直接向我 汇报。

在产品和研发方面:彻底重写了CSDN用户管理功能(以下称passport),数据库也迁移到了Linux下MySQL;编写整个CSDN的搜索部分代码,提供了全文检索;对CSDN网站全站导航进行了重新设计和改造;开发了新的针对移动的cmdn社区(后废弃)。

由于CSDN各产品线都是独立的,因此需要统一的用户注册登录管理产品passport。在过去,passport代码极其臃肿,不同产品线的登 录代码直接hard code在源码中;数据库使用SQL Server,大量有用无用的存储过程调用,用户表数据量庞大,而且非常多无用冗余字段,查询缓慢,用户时常无法登录;而且CSDN用户注册和登录页面的 用户体验极其糟糕;最后CSDN很多产品以各自的方式调用passport,导致passport不得不维护多套协议适配各种产品。因此欲改进CSDN网 站,必先动passport,而一动passport,则牵一发而动全身,CSDN所有产品都可能出问题。因此在动手重写passport之前,我耐心等 待了好几个月,一方面一遍一遍做CSDN产品线梳理,尽可能找出所有耦合产品提前解决隐患;另一方面等待各部门高管一致表态愿意承担各自产品线出问题的代 价来支持重写。

新的passport产品从2010年9月设计到2011年元旦上线花了3个月时间,passport产品看似需求简单,代码量不大,然而却有非 常多的细致工作:重新设计整个用户登录验证功能,以确保更高的账号安全性;尽可能的测试所有CSDN需要登录验证的产品线,跨不同编程语言,以确保兼容 性;由于账号数据库达到了1700多万条,必须使用缓存来提高用户账号数据查询效率;详细的登录日志记录、授权记录以及账号审核功能以确保误操作的可追溯 和找回;庞大的数据量从SQL Server迁移到Linux下MySQL的迁移效率问题;重新设计用户注册,登录和账号设置,改进用户体验等等。新的passport产品上线并不引人 注目,但意义非常重大,它是第一个真正讲究产品设计和用户体验的CSDN产品,而且解决了passport问题,其他产品才有可能改进。

这段时间遇到的最大困难是我始料未及的团队融合问题:9月和10月集中入职了10名新员工,整个部门有一半都是新人,但到11月有5名新员工离 职。公司招聘新人留不住是个很严重的问题,这也是我进CSDN以来遇到的最严峻的挑战。新员工离职虽然有很多原因,但最核心问题在于两点:

1、新员工入职过多过于密集比例过高,我没有高度重视新员工的融入问题。后来关于新员工融入也有很多经验和教训:新人入职前两周对公司的印象决定 了他对公司的最终印象;新人入职第一个月适应与否决定了他在这家公司会待多长时间。那段时间集中入职了10个新人,没有制定系统的新人融入计划,而我又有 一周多时间不在北京,新人茫然无措。

2、虽然经过我前几个月的调整,但当时部门都是工作多年的老人,老的风气和习惯已经形成了很顽固的不良文化,新人很难适应这种不良的文化和环境,同时又被个别老员工灌输了太多公司n年前沉芝麻烂谷子的负面八卦,工作情绪受到很大的影响。

公司文化说起来很飘渺,但它又实实在在影响每个员工。一个新员工进入一家公司,要么被公司的文化同化,要么自己适应不了离开。而这次是大批新员工 入职,老的公司文化和新员工群体之间的融合问题突然变得很尖锐,大批新员工离职就是一个很糟糕的信号。我当时感觉到这是个生死攸关的挑战和契机:如果任由 这种情况发展下去,老的公司文化会迅速吞噬掉新的员工,然后整个部门回到一开始死气沉沉的状况,我所有的努力都会化为泡影。一鼓作气再而衰三而竭,这次如 果不能借新员工入职来冲击和改变老的公司文化,而是任由新员工全部流失,以后未必能有第二次机会和心气去改变整个团队的风气,因此我下定决心把整个部门风 气彻底扭转过来,并且针对性采取了一些措施:

1、加强部门内部的沟通和交流,打造一个交流氛围浓厚,成员关系很融洽的部门。鼓励员工工作时间经常热烈讨论和交流,甚至说说笑笑,无拘无束。
2、重视团队内部的分享,团队间轮流进行内部培训,将自己最近钻研的工作和技术心得向大家分享
3、在部门内部加强团队管理,树立赏罚分明,及时落实的威信,发现问题迅速解决避免拖延;
4、抓重点团队主次分明,在团队建设积极向上的交流氛围,推动整个部门风气的转变;
5、坐在员工旁边,及时和员工交流,杜绝各种杂事,拿出时间多和员工交流;

我原来有自己独立的办公隔间,但坐在隔间里面不方便和员工直接交流,也不利于发现团队的问题。所以我就干脆搬到员工的工位坐,这段时间主抓哪个团 队的工作,就搬到那个团队中间的位置坐,随时随地和员工沟通,检查员工工作,及时解决团队出现的问题,并且这样做也可以身体力行的教会员工怎样正确的做事 情,怎样达到我要求的工作标准,怎样成为一个优秀的员工,怎样避免犯不应该出现的错误;此外我给自己设置了3个月的冻结期,从11月到春节前除了必须在上 海出席的SD大会之外,杜绝一切外事活动,专心致志在公司蹲点练好部门的内功;在抓团队工作的时候,深入到业务层面提高工作要求,如对研发团队我会做详细 的code review,对产品团队我会仔细检查每个产品原型设计。

经过3个月的不懈努力,整个部门的风气被彻底扭转过来了,新人和老人开始融合成为了一个集体,团队的执行力得到了巨大的改变。过去我下达的一个命 令,要我自己一个环节一个环节盯下去才能完成,这个时候下达一个命令,整个团队就会动起来自己按部就班的执行下去,并且这种风气反过来开始影响老的员工, 推动老员工开始转变。我所管理的部门从3月底接手的时候被公认是公司最差的部门,到年底变成了公司风气最好的部门。

2011年2月 - 2011年7月

虽然部门的风气已经开始走上了健康的自我循环,但部门缺岗仍然很严重,过完春节之后整个部门有20个员工,这个时候遇到的最大问题就是招聘荒了。 今年2月-3月是整个IT行业招聘都特别困难的时期,一方面由于各大互联网公司特别是电子商务和团购网站的疯狂招聘,另一方面IT人才供给开始减少,连大 公司招人都很困难,更不要说我们了。在4月之前长达1个半月招聘期间一个新人都没有招到,而且由于各种原因陆续有人离职,到4月,部门员工又缩减到14 人,团队又需要重新build了。

从2月到5月份我的核心工作就是招人和build团队,整个招聘状况从4月份开始转变,4月-5月招聘了大量的新人,同时也有很多公司内部转岗的 员工,到现在,整个部门人员已经扩张到了11个团队总共36人。由于有了去年的惨痛教训,对新人入职进行了高度重视,因此虽然入职本部门有22个新人,远 超过原部门员工14人,但新人融合情况非常好,整个部门蒸蒸日上:

1、我将带新人列入各个团队经理的绩效考核项目之内,加强对团队经理带新人方面的考评;
2、每周和各团队经理沟通新人入职后的表现状况,入职前两周几乎天天询问团队经理,对新人出现的各种状况立刻采取应对措施;
3、我定期对入职新人进行本部门的新人培训,帮助新人迅速了解部门状况;
4、对团队经理们进行管理培训,教会他们如何带好新人;

由于一方面高度重视新人适应期,另一方面经过去年底的风气扭转已经形成了良好的部门文化氛围,因此除了个别拿我们当去大公司跳板的无良新人,绝大 部分新人都很好的融入了部门,并且随着新鲜血液的不断加入,很多新人工作的冲劲和心气对部门文化氛围不但没有冲淡,反而对部门文化进行了很大的加强,而这 种更加活跃,更加积极主动承担责任做事情的态度反过来又不断激励了部门老人改变自己的作风,以更加积极的态度工作,新人和老人之间的互相促进起了美妙的化 学反应。

在部门团队build方面,扩张到了11个团队:3个产品团队:产品设计,产品UI,平台UI;4个研发团队:PHP,Ruby,.net和搜 索;3个运营团队:社区运营,内容审核,高校俱乐部,此外还有系统运维团队,这11个团队经理直接向我汇报,整个部门职能团队基本齐全了。在我来CSDN 之前,公司没有产品设计团队,产品设计方面一片空白;社区运营团队也十分残缺,干的活根本就达不到运营的基本要求,所以我针对性的build了产品团队和 运营团队:

1、设立了产品设计团队,制定了规范的产品流程,强调以互联网产品设计驱动整个产品设计,UI,研发和运营流程,将目前公司所有平台级产品开发统统规范起来了;
2、搭建了两个职能分开的UI设计团队:产品UI团队紧密配合产品设计团队,负责产品UI设计和页面制作;平台UI团队负责公司商务,会务,编辑,市场以及平面宣传品方面的设计;
3、对运营团队进行了重点建设:分设CSDN和ITeye的网站运营和客服人员,搭建了一支社区运营编辑团队,此外在公司内部进行社区运营之道的系列讲座,以及对社区团队进行专业知识培训,灌输运营理念,强化运营人员的专业水平;

在产品方面,根据公司整体战略和其他部门的需求,改版上线了CSDN博客产品;重写改版了CSDN学生大本营和高校俱乐部;重写改版了CSDN移 动频道,云计算频道,对资讯频道和软件研发频道都进行了相应的改版;ITeye网站制定了全站整体的产品改版和改进计划,已完成了资讯产品改版,博客产品 改版,精华频道开发,资讯采集和管理平台开发,审核系统开发,多账号登录等,正在和即将完成的还有全站消息通知系统开发,群组产品开发,网站首页改版,问 答改版,论坛改版;此外还有CSDN下载产品,外包产品和俱乐部产品的设计和研发工作等等,这些产品将在今年下半年陆续上线发布。

CSDN博客是其中开发周期很长的产品,由于我主要精力都放在招聘和团队建设上,放松了对博客产品的管理,而手下产品经理的能力和权威尚不足以独 自掌控博客产品,因此到5月底,产品开发陷入了失控的边缘。这个时候我召集产品,UI,研发和运维团队进行了博客产品特别团队的立项,下了死命令6月底产 品必须公测,由我主持所有相关人员每天下班前开会,review每天进度,同时产品经理每天根据会议情况写日报抄送给大家,我亲自抓每个产品细节和每天项 目进度。两周之后,产品状况得到了彻底扭转,此时我让运营团队也加入特别项目组,开始进行博客上线前期的运营准备,包括邀请用户内测,定期发布公告,整理 博客专家等等,最终博客产品顺利上线并且取得了良好的效果。

CSDN博客产品的成功推出和后续成功的运营对团队有很大的鼓舞作用,它并非各团队配合最好的产品,但从博客产品开始,我手把手教运营团队如何处 理一个产品从上线前准备,到上线,到上线后持续运营,以及如何制定专家运营策略,博客推广策划,如何掌握运营节奏等。在CSDN博客产品上线之 前,CSDN的运营还没入门,从博客产品开始有了真正意义上的运营。此外产品,UI,研发和运营团队从博客产品开始进行充分的磨合,中间暴露了很多问题, 也取得了一些宝贵的经验:今后核心产品的研发从立项开始,我就会召集产品设计,产品UI,产品研发和运营四个团队参与,从一开始就紧密配合,共同完成好一 个产品的设计,研发,上线和运营流程。

个人总结

回顾这一年多的工作,觉得自己取得的成绩有以下方面:

1、在公司的大力支持下,彻底改变了部门的风气,打造了一支积极进取,配合默契,对工作有责任心,执行力高的团队,尤其让我欣慰的是当我出差一周不在北京期间,整个部门仍然有条不紊各负其责的运转,所有工作按计划照常推进;
2、在部门内部树立了规范的制度化管理,各个团队的工作都是在有目标有计划有策略开展,整个部门做事情条理性很强,思路很清晰;
3、打造了一支专业的产品设计团队,正在培养一支专业的运营团队;制定了从产品设计,UI设计到研发和运营配合良好的产品流程,个人觉得这种专业化的产品团队配合在国内互联网公司并不多见;
4、已经做了一些成功的产品,正在继续做更多成功的产品,这些产品将在今年下半年集中发布

亦留下不少遗憾和不足:

1、针对我接手前团队一盘散沙的现状,进行了一系列部门调整,说到底宗旨只有一条:进行中央集权式管理。将所有决策权和团队协调工作,跨部门协调 工作全部集于我一人,依靠我在公司的地位、威望和个人能力来推动所有的事情往前走。这样做的好处当然是立竿见影的解决掉了所有的问题,团队执行力也非常 好,通过一年的努力也彻底改变了部门状况。但负面影响就是我很忙也很累,直接向我汇报工作的人就有11个人,加上部门常规管理,帮助个别团队解决问题,跨 部门工作协调,公司高管会议等等,每天都忙得不可开交。

我也考虑在合适的时间将权力下放,将一个大部门再分拆成三个子部门,分别是:产品UED部门,下辖产品设计,产品UI和平台UI3个团队;研发部 门,下辖PHP,Ruby, .net,搜索和运维5个团队;运营部门,下辖社区运营,内容审核,高校俱乐部和架构师俱乐部4个团队。产品UED部门和运营部门设立部门主管职位,研发 部门主管我自己兼任,但改设首席架构师职位,负责架构设计和code review。但目前主要的障碍就是缺少主管级人才,而且整个部门团队都是我手把手带出来的,工作方式已经深深打上了我的烙印,要寻找到能够从气质上能力 上都符合的主管殊为不易。

2、缺人,严重的缺人! 目前的产品团队只有2个人,还大大的缺少产品设计人员和产品经理,以致于我自己和产品人员都身背多个核心产品的设计和管理工作,负担超重;搜索团队还缺少 经验丰富,对数据挖掘有研究的资深工程师,以致于严重影响到了规划中的数据分析工作;网站编辑还缺人,ITeye网站的运营最缺少的就是优秀的网站编 辑,ITeye网站品牌的重振需要编辑人才的加盟;最后有经验的Ruby工程师,我强烈的召唤你!

如今CSDN无论从我管理的部门还是整个公司,都在蒸蒸日上,正处在需要更多优秀的人才大战拳脚的时候,在这里,你可以在一个非常舒适和开放的文化环境中工作,飞速的提升你的经验和能力,做出很多令人瞩目的成绩!

posted @ 2011-08-01 09:43 芝麻开门 阅读(67) 评论(0) 编辑
摘要: 步骤:一、新建工程,添加ibatis、spring和struts的jars;二、数据库设计.三、POJO类.四、pojo类配置文件编写五、ibatis主配置文件编写【主配置文件只剩下sqlMap了】六、dao接口和接口实现七、service接口和接口实现八、struts action实现及struts-config.xml配置九、spring配置文件的内容【牵扯到ibatis和struts的整合】十、测试一、新建工程,添加ibatis、spring和struts的jars;二、数据库设计. mysql数据库:Sql代码useibatis;droptableifexistsuser;create阅读全文
posted @ 2011-04-21 21:20 芝麻开门 阅读(995) 评论(0) 编辑
一、Spring的IoC(Inversion of Control)。
这是Spring中得有特点的一部份。IoC又被翻译成“控制反转”,也不知道是谁翻译得这么别扭,感觉很深奥的词。其实,原理很简单,用一句通俗的话来说:就是用XML来定义生成的对象。IoC其实是一种设计模式,Spring只是实现了这种设计模式。

这种设计模式是怎么来的呢?是实践中逐渐形成的。

第一阶段:用普通的无模式来写Java程序。一般初学者都要经过这个阶段。
第二阶段:频繁的开始使用接口,这时,接口一般都会伴随着使用工厂模式。
第三阶段:使用IoC模式。工厂模式还不够好:(1)因为的类的生成代码写死在程序里,如果你要换一个子类,就要修改工厂方法。(2)一个接口常常意味着一个生成工厂,会多出很多工厂类。
    可以把IoC模式看做是工厂模式的升华,可以把IoC看作是一个大工厂,只不过这个大工厂里要生成的对象都是在XML文件中给出定义的,然后利用Java的“反射”编程,根据XML中给出的类名生成相应的对象。从实现来看,IoC是把以前在工厂方法里写死的对象生成代码,改变为由XML文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。

    IoC中最基本的Java技术就是“反射”编程。反射又是一个生涩的名词,通俗的说反射就是根据给出的类名(字符串)来生成对象。这种编程方式可以让对象在生成时才决定要生成哪一种对象。我在最近的一个项目也用到了反射,当时是给出一个.properties文本文件,里面写了一些全类名(包名+类名),然后,要根据这些全类名在程序中生成它们的对象。反射的应用是很广泛的,象Hibernate、String中都是用“反射”做为最基本的技术手段。

    在过去,反射编程方式相对于正常的对象生成方式要慢10几倍,这也许也是当时为什么反射技术没有普通应用开来的原因。但经SUN改良优化后,反射方式生成对象和通常对象生成方式,速度已经相差不大了(但依然有一倍以上的差距)。


    所以要理解IoC,你必须先了解工厂模式和反射编程,否则对它产生的前因后果和实现原理都是无法理解透彻的。只要你理解了这一点,你自己也完全可以自己在程序中实现一个IoC框架,只不是这还要涉及到XML解析等其他知识,稍微麻烦一些。


    IoC最大的好处是什么?因为把对象生成放在了XML里定义,所以当我们需要换一个实现子类将会变成很简单(一般这样的对象都是现实于某种接口的),只要修改XML就可以了,这样我们甚至可以实现对象的热插拨(有点象USB接口和SCIS硬盘了)。

    IoC最大的缺点是什么?(1)生成一个对象的步骤变复杂了(其实上操作上还是挺简单的),对于不习惯这种方式的人,会觉得有些别扭和不直观。(2)对象生成因为是使用反射编程,在效率上有些损耗。但相对于IoC提高的维护性和灵活性来说,这点损耗是微不足道的,除非某对象的生成对效率要求特别高。(3)缺少IDE重构操作的支持,如果在Eclipse要对类改名,那么你还需要去XML文件里手工去改了,这似乎是所有XML方式的缺憾所在。

    总的来说IoC无论原理和实现都还算是很简单的。一些人曾认为IoC没什么实际作用,这种说法是可以理解的,因为如果你在编程中很少使用接口,或很少使用工厂模式,那么你根本就没有使用IoC的强烈需要,也不会体会到IoC可贵之处。有些人也说要消除工厂模式、单例模式,但是都语焉不详、人云亦云。但如果你看到IoC模式和用上Spring,那么工厂模式和单例模式的确基本上可以不用了。但它消失了吗?没有!Spring的IoC实现本身就是一个大工厂,其中也包含了单例对象生成方式,只要用一个设置就可以让对象生成由普通方式变单一实例方式,非常之简单。

   总结:
   (1)IoC原理很简单,作用的针对性也很强,不要把它看得很玄乎。
   (2)要理解IoC,首先要了解“工厂、接口、反射”这些概念。
二、Spring中IOC的实现
了解了IOC模式的思想以及其优点,再来学习其实现。上面大致描述了PicoContainer以及Spring各自对IOC的实现,这篇来详细看一下Spring中它的实现。

Spring中IOC贯穿了其整个框架,但正如martinflower所说:“saying that these lightweight containers are special because they use inversion of control is like saying my car is special because it has wheels”,IOC已经称为框架设计中必不可少的部分。就实现上来讲Spring采取了配置文件的形式来实现依赖的注射,并且支持Type2 IOC(Setter Injection)以及Type3 IOC(Constructor Injection)。

Spring中IOC的实现的核心是其Core Bean Factory,它将框架内部的组件以一定的耦合度组装起来,并对使用它的应用提供一种面向服务的编程模式(SOP:Service-Orient Programming),比如Spring中的AOP、以及持久化(Hibernate、ibatics)的实现。
    首先从最底层最基础的factory Bean开始,先来看org.springframework.beans.factory.Bean

Factory接口,它是一个非常简单的接口,getBean方法是其中最重要的方法,Spring通常是使用xml来populate Bean,所以比较常用的是XMLFactoryBean。

用一个简单的示例看一下其用法。首先写下两个Bean类:

ExampleBean 类:

public class ExampleBean {

       private String psnName=null;

       private RefBean refbean=null;

       private String addinfo=null;



       public String getAddinfo() {

              return getRefbean().getAddress()+getRefbean().getZipcode();

       }

       public String getPsnName() {

              return psnName;

       }

       public void setPsnName(String psnName) {

              this.psnName = psnName;

       }

       public void setRefbean(RefBean refbean) {

              this.refbean = refbean;

       }

       public RefBean getRefbean() {

              return refbean;

       }

       public void setAddinfo(String addinfo) {

              this.addinfo = addinfo;

       }

}



RefBean类:

public class RefBean {

       public String getAddress() {

              return address;

       }

       public void setAddress(String address) {

              this.address = address;

       }

       public String getZipcode() {

              return zipcode;

       }

       public void setZipcode(String zipcode) {

              this.zipcode = zipcode;

       }

       private String zipcode=null;

       private String address=null;

}

其xml配置文件 Bean.xml 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

  <bean id="exampleBean" class="test.ExampleBean">

    <property name="psnName"><value>xkf</value></property>

    <property name="refbean">

       <ref bean="refBean"/>

    </property>

  </bean>

  <bean id="refBean" class="test.RefBean">

  <property name="address"><value>BeiJing</value></property>

  <property name="zipcode"><value>100085</value></property>

  </bean>

</beans>



然后可以写个测试类来测试,当然,需要Spring中的Spring-core.jar以及commons-logging.jar,当然在elipse中可以通过安装spring-ide插件来轻松实现。

public class Test {

       public static void main(String[] args){

              try{

              Resource input = new ClassPathResource("test/Bean.xml");

              System.out.println("resource is:"+input);

              BeanFactory factory = new XmlBeanFactory(input);

              ExampleBean eb =

              (ExampleBean)factory.getBean("exampleBean");

              System.out.println(eb.getPsnName());

              System.out.println(eb.getAddinfo());

       }

       catch(Exception e){

              e.printStackTrace();

       }

}

这样,通过BeanFactory的getBean方法,以及xml配置文件,避免了在test类中直接实例化ExampleBean,消除了应用程序(Test)与服务(ExampleBean)之间的耦合,实现了IOC(控制反转)或者说实现了依赖的注射(Dependency Injection)。

">"refbean">

       <ref bean="refBean"/>

    </property>

  </bean>

  <bean id="refBean" class="test.RefBean">

  <property name="address"><value>BeiJing</value></property>

  <property name="zipcode"><value>100085</value></property>

  </bean>

</beans>



然后可以写个测试类来测试,当然,需要Spring中的Spring-core.jar以及commons-logging.jar,当然在elipse中可以通过安装spring-ide插件来轻松实现。

public class Test {

       public static void main(String[] args){

              try{

              Resource input = new ClassPathResource("test/Bean.xml");

              System.out.println("resource is:"+input);

              BeanFactory factory = new XmlBeanFactory(input);

              ExampleBean eb =

              (ExampleBean)factory.getBean("exampleBean");

              System.out.println(eb.getPsnName());

              System.out.println(eb.getAddinfo());

       }

       catch(Exception e){

              e.printStackTrace();

       }

}

这样,通过BeanFactory的getBean方法,以及xml配置文件,避免了在test类中直接实例化ExampleBean,消除了应用程序(Test)与服务(ExampleBean)之间的耦合,实现了IOC(控制反转)或者说实现了依赖的注射(Dependency Injection)。
posted @ 2011-04-21 20:08 芝麻开门 阅读(43) 评论(0) 编辑

一、MVC简介

  概括起来MVC的优点主要有一下方面:

  1)多个视图可以对应一个模型。按MVC设计模式,一个模型对应多个视图,可以减少代码的复制及代码的维护量,一旦模型发生改变,也易于维护

  2)模型返回的数据与显示逻辑分离。模型数据可以应用任何的显示技术,例如,使用JSP页面、Velocity模板或者直接产生excel文档等

  3)应用被分隔为三层,降低了各层之间的耦合,提供了应用的可扩展性

  4)控制层的概念也很有效,由于它把不同的模型和不同的视图组合在一起,完成不同的请求。因此,控制层可以说是包含了用户请求权限的概念

  5)MVC更符合软件工程化管理的精神。不同的层各司其职,每一层的组件具有相同的特征,有利于通过工程化和工具化产生管理程序代码

  对于MVC的概念性的东西也就废话到此,其关键的地方就是各个模块的实现技术分别是什么。

  二、Struts2简介

  Struts2是一个兼容Struts1和WebWork的MVC框架。

  Struts2的简单处理流程如下:

  1)浏览器发送请求

  2)中心处理器根据struts.xml文件查找对应的处理请求的Action类

  3)WebWork的拦截器链自动对请求应用通用功能,例如:WorkFlow、Validation等功能

  4)如果Struts.xml文件中配置Method参数,则调用Method参数对应的Action类中的Method方法,否则调用通用的Execute方法来处理用户请求

  5)将Action类中的对应方法返回的结果响应给浏览器

  三、Struts2与Struts1对比

四、Struts2与WebWork对比

  Struts2实际上就是WebWork2.3,不过,Struts2还是与WebWork有少许的差别:

  1)Struts2不再支持内置IOC容器,改用Spring的IOC容器

  2)Struts2对于Webwork的一些ajax的特性的标签改用Dojo进行替换

  //----------------------------------------------------

  以上内容转载。

  我就只说一句,Struts2是MVC的一种实现,Struts2运行机理相比Struts1有很大的不同,Struts2是基于WebWork的。

  下面开始说怎么去运行一个Struts2程序。所需jar包等,请到http://struts.apache.org下载

  1、 myeclipse新建web project

  2、 下载Struts2之后加压,找到struts2-blank-xxx.war 再解压

  3、 找到Struts2-blank中lib,把所有的*.jar复制到 myeclipse所建的web project的lib中

  4、 配置Struts2的过滤器:在web project的web.xml中配置

  Xml代码   

<filter> 
    <filter-name>struts2</filter-name> 
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> 
</filter> 
 
<filter-mapping> 
    <filter-name>struts2</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping>

  5、 新建以下JSP页面

  login.jsp

  Html代码   

<%@ page language="java" import="java.util.*" pageEncoding="gbk"%> 
<html> 
 <head> 
  <title>My JSP 'index.jsp' starting page</title> 
 </head> 
 <body> 
 <form action="test.action" method="post"> 
  用户名:<input type="text" name="username"><br> 
  密码:<input type="text" name="pwd"><br> 
  <input type="submit" value="Submit"> 
 </form> 
 </body> 

</html> 

 

 ok.jsp

  Html代码   

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%> 
<html> 
 <head> 
  <title>My JSP 'ok.jsp' starting page</title> 
 </head> 
 <body> 
 OK!! 
 </body> 
</html> 

  no.jsp

  Html代码   

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%> 
<html> 
 <head> 
 <title>My JSP 'no.jsp' starting page</title> 
 </head> 
 <body> 
 NO!! 
 </body> 
</html> 

  6、 新建一个类

  TestAction.java

  Java代码   

/** 
 * 
 */ 
package com.struts2.action; 
 
/** 
 * @author Administrator 
 * 
 */ 
public class TestAction { 
 /** 
 * 注意:属性名字要和jsp页面的表单元素名字一样,并且提供getter setter方法 
 */ 
 private String username; 
 private String pwd; 
 
 public String execute() { 
 if (username.equals(pwd)) { 
  return "OK"; 
 } else { 
  return "NO"; 
 } 
 } 
 
 public String getUsername() { 
 return username; 
 } 
 
 public void setUsername(String username) { 
 this.username = username; 
 } 
 
 public String getPwd() { 
 return pwd; 
 } 
 
 public void setPwd(String pwd) { 
 this.pwd = pwd; 
 } 
 
} 

  7、 在src下建立struts.xml 并配置刚才建立的Action

  Xml代码   

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE struts PUBLIC 
  "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 
  "http://struts.apache.org/dtds/struts-2.0.dtd"> 
 
<struts> 
 <package name="default" namespace="/" extends="struts-default"> 
 <action name="test" class="com.struts2.action.TestAction"> 
  <result name="ok">/ok.jsp</result> 
  <result name="no">/no.jsp</result> 
 </action> 
 </package> 
</struts> 

  8、 部署运行

  //--------------------------------------------------------

  总结:TestAction 中要有一个execute方法,并且返回的值在struts.xml中配置过。只要表单提交到TestAction下,Struts2会帮我们按名接收表单数据。返回的值,代表要跳转的页面。

posted @ 2011-04-21 20:07 芝麻开门 阅读(313) 评论(0) 编辑
Web服务代理是支持.net的编程语言文件,由.net框架提供的WSDL工具自动生成。代理类不包含任何应用程序逻辑。相反,他包含关于如何传递参数和检索结果的传输逻辑,还包含Web服务中的方法及原型列表。代理类可以从任何WSDL文件创建。

       可以像访问com对象一样访问Web服务。要访问Web服务,需要从本地计算机上的Web服务的WSDL文档创建代理类。.net提供了名为WSDL.exe的工具以自动生成代理类文件。下面详细说明其创建和使用过程:

1、  新建一个asp应用程序(#C)工程,工程名为TeachShow,在TeachShow工程中创建一个文件夹Charpter8,在该文件夹下创建一个新的Web服务,取名为:Computer.asmx

2、  切换到代码视图,编写下面的代码:

[WebMethod(Description="用于相加运算", EnableSession=false)]

        public int Add(int a,int b)

        {

            return a+b;

        }

        [WebMethod(Description="用于相减运算", EnableSession=false)]

        public int Sub(int a,int b)

        {

            return a+b;

        }

        [WebMethod(Description="用于相乘运算", EnableSession=false)]

        public int Multi(int a,int b)

        {

            return a*b;

        }

        [WebMethod(Description="用于相除运算", EnableSession=false)]

        public double Devide(int a,int b)

        {

            return Convert.ToDouble(a)/Convert.ToDouble(b);

       3、按F5编译整个工程(这一步一定要做,如果不做第4步无法实现)

4、打开MS.net 2003的命令提示工具,输入:C:\>wsdl http://localhost/TeachShow/Charpter8/FirstAndUse/Computer.asmx /n:ComputerNameSpace,其中,ComputerNameSpace是自定义的命名空间。提示如下:

Microsoft (R) Web 服务描述语言实用工具

[Microsoft (R) .NET Framework,版本 1.1.4322.573]

Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.

正在写入文件“C:\Computer.cs”。

5、注意,此时在C:盘(其实就是命令提示符的当前目录)下生成一个和Computer.asmx相同文件名的C#源文件Computer.cs

6、编译Computer.cs文件,在命令提示符下输入如下命令:C:\>csc /out:ComputerDll.dll /t:library /r:System.Web.Services.dll c:\Computer.cs。其中,/out:ComputerDll.dll是要输出的dll文件,/t:library是输出文件类型,/r:System.Web.Services.dll是要引用的组件,c:\Computer.cs是第4步生成的C#文件。

7、此时,将会在C:盘下生成一个叫ComputerDll.dll的文件,要使用这个文件,必须复制到TeachShow文件夹下的bin目录下。默认情况下为:C:\Inetpub\wwwroot\TeachShow\bin

8、新建一个名为TestWSDL.aspxWEB窗体文件,并添加一个引用,将刚才生成的ComputerDll.dll文件作为引用添加到工程中。

9、在TestWSDL.aspx窗体的Load事件中编写代码:

                     ComputerNameSpace.Computer com=new ComputerNameSpace.Computer();

            this.Response.Write("和:"+com.Add(45,65).ToString()+"

posted @ 2011-04-20 19:41 芝麻开门 阅读(60) 评论(0) 编辑
人人网的系统架构

今天在网上看到人人网使用的开源软件列表 ,人人网的架构师写的,看完后,大概了解了人人网的架构信息

数据层

使用MySQL ,同时使用Tokyo Cabinet(Key-value的存储引擎,简称TC)做一个数据冗余,TC代替MySQL做存储,例如搜索结果页的用户资料,但Tokyo Cabinet没有网络处理能力,需要使用Tokyo Tyrant以提供网络接入能力,并调用Tokyo Cabinet的API进行持久化存储

Tokyo Tyrant其实也是Tokyo Cabinet的作者开发的,主要是支持Memcached传输协议的网络接口,可以理解为Tokyo Tyrant处理网络连接,协议解析,然后调用Tokyo Cabinet的API来完成持久化存储

服务端

Web Server : Nginx, 使用Nginx的代理能力,做跨IDC的请求代理,同时与Java Server–Resin搭配,解决Resin网络连接处理能力弱的问题

Java Server: Resin 替代Tomcat作为Java服务器

代理服务器 : Squid 做图片文件的反向代理缓存

Linux服务器集群系统: LVS(Linux Virtual Server),使用它的4层的负载均衡,替代了很多硬件的负载均衡设备
框架

Java web框架: Struts,王兴同学一开始写校内网果然是用structs,现在的人人网开始慢慢舍弃原有的框架,并自己开发了一个web框架,传闻将来也会开源出来

搜索引擎框架: 基于Lucence提供搜索人的服务

网络框架:Netty,一个Java的网络框架,和apache的mina类似,但比mina更高效,用来提供一些小的服务

服务器系统监控

ganglia Ganglia是一个跨平台可扩展的,高性能计算系统下的分布式监控系统,如集群和网格

应用层缓存

Memcached   一个纯内存的key-value的cache系统,使用spymemcached作为java的Client

ICE : 一个跨语言的网络通讯框架,框架本身提供了强大的通讯能力,管理工具,负载均衡方案,其跨语言能力也是一个很大的亮点,基于这个框架之上,我们选用合适的语言来提供合适的服务,比如我们使用C++来开发Cache服务,使用Java来开发一些逻辑服务。框架本身可以很重,也可以很轻,具体要看你怎么用:)

Memcached和ICE的缓存服务区别

对Cache的操作粒度不一样,Memcached对Cache对象以binary byte作为一个整体来操作,需要频繁的序列化和反序列化,我们使用ICE提供的Cache服务,可以以Cache对象的一个或者多个字段来操作,比如一个用户对象,我们可以只更新它的姓名。

 

 

人人网中间层:问题篇
由开源软件组成的系统

与很多大型的网站一样,人人网的系统全部是由开源软件构建的。使用Nginx做前端接入,resin做容器,Memcached做通用cache,MySQL做数据库,使用Linux操作系统。
除了上述的部分外,人人网还有一个与众不同的中间层。中间层以服务的形式存在,位于MySQL和resin中间,提供高并发低成本的数据访问层。
数据库的压力

在上述结构系统中,数据库的性能往往成为系统瓶颈。人人网在发展的过程中不断重构,改变最大的就是数据库部分。大概的步骤是“优化SQL”,“业务拆分”,“垂直拆分”和“水平拆分”几个阶段,关于数据库优化的细节将来再引用到这里。
经过优化后的数据库,单台可以承担每秒3000次的主键查询。再提高性能的优化,我们采用的方案是使用中间层。
性能目标

增加中间层可以在不增加服务器数量的前提下,提高服务的整体性能,并且提高系统的可扩展性。这里简要列举一些使用中间层服务优化的效果。
实时更新的数据

用户的个人信息数据,目前的写操作500次/秒,读操作2万次/秒。这些数据分布在数十个数据表中,如果用数据库做10次主键查询,需要的时间将会非常可观。中间层的缓存服务把这个性能稳定在了99.9%的请求时间小于20ms。
判断好友关系,读操作900次/秒。这个操作现在使用6G内存存储了所有的好友关系,在2ms内返回任意两人的好友关系。
关联查询,仅好友列表就有1300次/秒。如果使用关联查询,数据库需要同步很多无用的字段。现在只需要两次内存请求,并且衍生出很多种类的排序。
大量聚合的访问

聚合的页面在SNS中是访问量最大的部分。首页集成的功能多达17个模块,这些模块之间的关系相对独立。为了快速的把这些数据集合在一起,就需要迅速获取数据。
我们对整体技术框架的要求是,关键页面执行时间要在100ms以内。
Session同步

众多的resin服务器之间,如何共享用户身份验证的结果,在各种session共享机制中,我们的方案是使用中间层服务来集中存储的。
待续

问题篇只是开端,接下来的“求解篇”将会分析人人网中间层的主要应用场景。“实践篇”将会举例一个典型的中间层服务。

人人网中间层:求解篇

为了提高性能,在人人网的技术结构中,在数据库和页面之间,有中间层。中间层高性能的基础是用内存代替磁盘。
用内存代替磁盘

数据库系统的最大瓶颈在磁盘IO,大量的小数据请求不是磁盘的强项。人人网中间层服务就是利用了内存代替硬盘的方法来提高整体性能。有了这层服务以后,以前的数据库关联查询被提前计算并缓存,需要访问时直接获取。
通用的Memcached缓存方案也有些不足,数据不能自己变化,也不能部分变化。于是人人网选择了自己实现缓存的方式。
在自己实现缓存的过程中,管理内存相对容易,通信协议是比较复杂的部分,我们在这方面选择了开源的Ice通信框架(http://www.zeroc.com)来完成繁琐的工作,至今它都工作的很好。
Ice通信框架在人人网完成了两件事,通信和定位。客户端通过IceGrid组件定位到需要的服务地址,将请求发送到中间层服务,中间层服务将结果返回。客户端只需要知道一个地址就可以找到所有的服务;同时,众多服务也可以在不同的服务器之间随意迁移。在现在的人人网有超过500个Ice写成的中间层服务在运行。
定制的内存数据

用Ice解决了通信和部署的问题后,中间层服务就是核心的数据结构管理。概括的说,就是灵活变化,保证速度。下面列举若干使用了中间层服务的情况
一份数据 多种排序

在人人网的好友页,有很多排序方式可以显示好友列表。每种列表都是从一个按ID排序的服务中获取的,再经过排序,缓存在各个顺序的列表中。
随时间变化的数据

在很多列表页面,都会显示“在线标志”,这个标志是冗余在各个列表的缓存当中,定期刷新的。这些需要和cache一起实现的业务逻辑,在人人网中间层当中非常普遍。
特殊类型

我们用了一个bit保存用户的激活状态。200M内存可以保存全部int范围的状态。并且查询和更新速度飞快。
接下来的实践篇将会用这个为例子展示中间层的实现。

人人网中间层:实践篇

之前的问题篇和求解篇描述了人人网在发展过程中遇到的问题,并且介绍了我们采用中间层来提高性能的解决方案。今天的实践篇将通过一个例子来实现一个中间层服务。
这个服务要达到的目的是快速的查询用户是否有效,数据将要使用bitset保存在内存中,每个用户一位,仅保存正整数约21亿,占用内存256M。
开始编码

下面的代码都在这个位置保存:http://gitorious.org/renren/bitserver。
接口定义

定义接口如下:
#include <Ice/BuiltinSequences.ice>
module renren {
struct BitSegment {
int begin;
int end;
Ice::ByteSeq data;
};
interface BitServer {
bool get(int offset);
Ice::BoolSeq gets(Ice::IntSeq offsets);
BitSegment getSegment(int begin, int end);
};
};

这个BitServer.ice文件,通过slice2cpp命令编译成为服务端的Skeleton文件:
slice2cpp -I/opt/Ice-3.3/slice BitServer.ice
服务端

有了上面生成的服务端文件后,就可以实现我们自己的业务功能了。
BitServerI.h和BitServerI.cpp,暂时只是实现了单个get的接口。
#ifndef __BitServerI_h__
#define __BitServerI_h__#include <BitServer.h>

#define SIZE_OF_BIT 2147483647
#include <bitset>

namespace renren
{

class BitServerI : virtual public BitServer
{
public:
void initialize();

virtual bool get(::Ice::Int,
const Ice::Current&);

virtual ::Ice::BoolSeq gets(const ::Ice::IntSeq&,
const Ice::Current&);

virtual ::renren::BitSegment getSegment(::Ice::Int,
::Ice::Int,
const Ice::Current&);
private:
std::bitset<SIZE_OF_BIT> bits_;
};

}

#endif
#include <BitServerI.h>
#include <Ice/Ice.h>int main(int argc, char** argv) {
int status = 0;
Ice::CommunicatorPtr ic;
try{
ic = Ice::initialize(argc, argv);
Ice::ObjectAdapterPtr adapter = ic->createObjectAdapter(“BitServer”);
renren::BitServerI* obj = new renren::BitServerI;
obj->initialize();
adapter->add(obj, ic->stringToIdentity(“BitServer”));
adapter->activate();
ic->waitForShutdown();
} catch (const Ice::Exception& e) {
std::cerr << e << std::endl;
status = 1;
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
status = 1;
} catch (…) {
std::cerr << “unknown exception” << std::endl;
status = 1;
}
if (ic) {
try {
ic->destroy();
} catch (const Ice::Exception& e) {
std::cerr << e << std::endl;
status = 1;
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
status = 1;
} catch (…) {
std::cerr << “unknown exception” << std::endl;
status = 1;
}
}
return status;
}

void
renren::BitServerI::initialize() {
for (int i=0; i<0xFFFFF;i=i+2) {
bits_[i]=true;
}
}

bool
renren::BitServerI::get(::Ice::Int offset,
const Ice::Current& current)
{
if(offset < 0) return false;
return bits_[offset];
}

::Ice::BoolSeq
renren::BitServerI::gets(const ::Ice::IntSeq& offsets,
const Ice::Current& current)
{
return ::Ice::BoolSeq();
}

::renren::BitSegment
renren::BitServerI::getSegment(::Ice::Int begin,
::Ice::Int end,
const Ice::Current& current)
{
return ::renren::BitSegment();
}
客户端

我们使用Java作为客户端,首先用slice2java工具生成Java的Proxy类。
slice2java -I/opt/Ice-3.3/slice BitServer.ice

然后自己实现客户端代码:
package renren;class BitServerAdapter {
private final String endpoints_;
private Ice.Communicator ic_;
private renren.BitServerPrx prx_;

public BitServerAdapter(String endpoints) {
this.endpoints_ = endpoints;
}

public void initialize() {
ic_ = Ice.Util.initialize();
prx_ = renren.BitServerPrxHelper.uncheckedCast(ic_.stringToProxy(endpoints_));
}

public boolean get(int id) {
return prx_.get(id);
}

public static void main(String[] args) {
BitServerAdapter adapter = new BitServerAdapter(args[0]);
adapter.initialize();
boolean ret = adapter.get(Integer.valueOf(args[1]));
System.out.println(ret);
System.exit(0);
}
}
性能测试

完成了代码,来测试一下性能吧。
首先启动服务器
target/bitserver –Ice.Config=config

再启动客户端
java -cp /opt/Ice-3.3/lib/Ice.jar:target/bitclient.jar \
renren.BitServerAdapter “BitServer:default -p 10000” 1022

在客户端调用增加循环50000次,单线程平均每秒处理一万次。

在多线程的环境下,单个服务器每秒可处理的请求8万次左右,已经超过了目前的需要。
 

posted @ 2011-04-13 20:07 芝麻开门 阅读(1012) 评论(0) 编辑
C:\ICEService\Registry\templates.xml

上面可以运行成 ICEGRID程序了。

可以把上面的exe 发布成 windows 服务:

1 . iceserviceinstall icegridregistry  config.grid   


2. iceserviceinstall icegridnode D:\MyIceGrid\config.node



再用 icegridadmin 增加 service 或用 IceGridGUI.jar 来管理 registery

.InstanceName=MyIceGrid

default -h 192.168.3.95 -p 12000

就可以管理了。

icegridadmin –-Ice.Config=D:\MyIceGrid\config.grid

 application add D:\MyIceGrid\application.xml

server start SimpleServer



http://blogold.chinaunix.net/u/8818/showart_706648.html


通过IceGrid的位置服务配置可以方便系统部署,具体优点不谈了,下面介绍下配置流程。
例子是ice/demo/IceGrid/simple。ice是采用3.2.1版本,测试时候可以自己下载。测试端,对Client.cpp简单做了修改。配置文件和修改后的Client.cpp 在conf.tar.gz内。用户可以下载,然后根据配置放在不同机器上。为了简化我用了一个表来说明,具体可参照测试部署表(1)        文件:    conf.tar.gz
大小:    1KB
下载:    下载



测试系统说明:
一个位置服务器192.168.10.6
两个node
    node4: 192.168.10.4
    node6: 192.168.10.6
 Client.cpp     测试机器     192.168.10.13
 config.grid     位置服务机器     192.168.10.6
 config.node4     服务节点     192.168.10.4
config.node6     服务节点    192.168.10.6
application.xml     位置服务机器    192.168.10.6

                                  部署表((1)
                   
1、配置位置服务

(1) 配置 config.grid
/************************************************************************/
IceGrid.InstanceName=DemoIceGrid

#
# The IceGrid locator proxy.
#
Ice.Default.Locator=DemoIceGrid/Locator:default -h 192.168.10.6 -p 12000

#
# IceGrid registry configuration.
#
IceGrid.Registry.Client.Endpoints=default -p 12000
IceGrid.Registry.Server.Endpoints=default
IceGrid.Registry.Internal.Endpoints=default
IceGrid.Registry.Data=db/registry
IceGrid.Registry.PermissionsVerifier=DemoIceGrid/NullPermissionsVerifier
IceGrid.Registry.AdminPermissionsVerifier=DemoIceGrid/NullPermissionsVerifier
IceGrid.Registry.SSLPermissionsVerifier=DemoIceGrid/NullSSLPermissionsVerifier
IceGrid.Registry.AdminSSLPermissionsVerifier=DemoIceGrid/NullSSLPermissionsVerifier

#
# IceGrid node configuration.
#
IceGrid.Node.Name=localhost
IceGrid.Node.Endpoints=default
IceGrid.Node.Data=db/node
IceGrid.Node.CollocateRegistry=1
#IceGrid.Node.Output=db
#IceGrid.Node.RedirectErrToOut=1

#
# Trace properties.
#
IceGrid.Node.Trace.Activator=1
#IceGrid.Node.Trace.Adapter=2
#IceGrid.Node.Trace.Server=3

#
# Dummy username and password for icegridadmin.
#
IceGridAdmin.Username=foo
IceGridAdmin.Password=bar
/************************************************************************/

(2).配置应用

application.xml文件
/************************************************************************/
<icegrid>
  <application name="Simple">
    <node name="node4">
      <server id="SimpleServer" exe="./server" activation="on-demand">
    <adapter name="Hello" endpoints="tcp" register-process="true">
      <object identity="hello" type="::Demo::Hello" property="Identity"/>
    </adapter>
      </server>
    </node>

    <node name="node6">
      <server id="SimpleServer2" exe="./server" activation="on-demand">
    <adapter name="Hello" endpoints="tcp" register-process="true">
      <object identity="hello2" type="::Demo::Hello" property="Identity"/>
    </adapter>
      </server>
    </node>
  </application>
</icegrid>
/************************************************************************/
说明:该文件主要配置节点和具体服务.主要配置node name和server id(注意不要重复)即可。

2、配置节点信息:
node4节点
config.node4文件
/***********************************************************************/
#
# The IceGrid locator proxy.
#
Ice.Default.Locator=DemoIceGrid/Locator:default -h 192.168.10.6 -p 12000

#
# IceGrid registry configuration.
#
IceGrid.Registry.Client.Endpoints=default -p 12000
IceGrid.Registry.Server.Endpoints=default
IceGrid.Registry.Internal.Endpoints=default
IceGrid.Registry.Data=db/registry
#IceGrid.Registry.PermissionsVerifier=DemoIceGrid/NullPermissionsVerifier
#IceGrid.Registry.AdminPermissionsVerifier=DemoIceGrid/NullPermissionsVerifier
#IceGrid.Registry.SSLPermissionsVerifier=DemoIceGrid/NullSSLPermissionsVerifier
#IceGrid.Registry.AdminSSLPermissionsVerifier=DemoIceGrid/NullSSLPermissionsVerifier

#
# IceGrid node configuration.
#
IceGrid.Node.Name=node4
IceGrid.Node.Endpoints=default
IceGrid.Node.Data=db/node
IceGrid.Node.CollocateRegistry=1
#IceGrid.Node.Output=db
#IceGrid.Node.RedirectErrToOut=1

#
# Trace properties.
#
IceGrid.Node.Trace.Activator=1
#IceGrid.Node.Trace.Adapter=2
#IceGrid.Node.Trace.Server=3

#
# Dummy username and password for icegridadmin.
#
IceGridAdmin.Username=foo
IceGridAdmin.Password=bar
/***********************************************************************/
该文件和config.grid基本一致
注意,IceGrid.Registry注册信息一定要有而且和config.grid一致。注意和node6不一样,因为node6
和位置服务在一个机器上,注册信息已经在config.grid配置了。

node6
config.node6 文件
/***********************************************************************/
#
# The IceGrid locator proxy.
#
Ice.Default.Locator=DemoIceGrid/Locator:default -h 192.168.10.6 -p 12000

#
# IceGrid node configuration.
#
IceGrid.Node.Name=node6
IceGrid.Node.Endpoints=default
IceGrid.Node.Data=db/node
#IceGrid.Node.Output=db
#IceGrid.Node.RedirectErrToOut=1

#
# Trace properties.
#
IceGrid.Node.Trace.Activator=1
#IceGrid.Node.Trace.Adapter=2
#IceGrid.Node.Trace.Server=3

#
# Dummy username and password for icegridadmin.
#
IceGridAdmin.Username=foo
IceGridAdmin.Password=bar

/***********************************************************************/

3、启动运行
1)启动位置服务
    icegridregistry --Ice.Config=config.grid
2)注册节点
    192.168.10.4机器:
         icegridnode --Ice.Config=config.node4  
    192.168.10.6机器:
     icegridnode --Ice.Config=config.node6
3)配置应用:
在 192.168.10.4机器上:
icegridadmin --Ice.Config=config.grid -e  "application add 'application.xml'"

4)测试
    ./client

    usage:
    t: send greeting
    p: send greeting2: shutdown server
    x: exit
    ?: help
选择t则调用 10.4机器;p则调用10.6机器
posted @ 2011-04-13 14:21 芝麻开门 阅读(597) 评论(0) 编辑
日志中记录到如下异常信息

 

事务(进程 ID 64)与另一个进程被死锁在 锁 | 通信缓冲区 资源上,并且已被选作死锁牺牲品。请重新运行该事务。
事务(进程 ID 92)与另一个进程被死锁在 锁 | 通信缓冲区 资源上,并且已被选作死锁牺牲品。请重新运行该事务。


业务逻辑中有批量insert和批量delete操作 ,没用到事务,多线程wroker程序

后台在表上添加索引解决。

 

SQL Server死锁总结

 

posted @ 2011-04-13 14:18 芝麻开门 阅读(89) 评论(0) 编辑
摘要: 转http://migege.com/archives/how-to-implement-a-simple-icegrid.html 在这里,我将建立一个拥有一个registry和两个node的IceGrid,其中node1与registry运行在同一台计算机上(但不同进 程,IP为192.168.3.95),node2运行在另一台计算机上(IP为192.168.3.68)。环境均为XP SP2+Ice 3.2.0。 首先在D盘(可以任意)下建立目录MyIceGrid,再建立子目录db及db\registry和db\node1,以存放registry和node1的数据。 将以下MyIceGri阅读全文
posted @ 2011-03-14 15:44 芝麻开门 阅读(407) 评论(0) 编辑
仅列出标题  下一页